--- /dev/null
+/*
+ Garmin GPS Database Reader
+
+ Copyright (C) 2005 Olaf Klein, o.b.klein@t-online.de
+ Mainly based on mapsource.c,
+ Copyright (C) 2005 Robert Lipe, robertlipe@usa.net
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "defs.h"
+#include "garmin_tables.h"
+#include "jeeps/gpsmath.h"
+
+#define MYNAME "gdb"
+
+#define MPSNAMEBUFFERLEN 1024
+#define MPSNOTESBUFFERLEN 4096
+#define MPSDESCBUFFERLEN 4096
+
+#define DEFAULTICONVALUE 18
+#define DEFAULTICONDESCR "Waypoint"
+
+#ifdef UTF8_SUPPORT
+# define GDB_UTF8_ENABLED 1
+#else
+# define GDB_UTF8_ENABLED 0
+#endif
+
+/* %%% local vars %%% */
+
+FILE *fin;
+static char *fin_name;
+static int gdb_ver = 1;
+static int gdb_debug = 0;
+route_head *gdb_hidden;
+
+/* %%% 1-1 functions from mapsource, should by shared!!! %%% */
+
+waypoint *
+gdb_find_wpt_q_by_name(const queue *whichQueue, const char *name)
+{
+ queue *elem, *tmp;
+ waypoint *waypointp;
+
+ QUEUE_FOR_EACH(whichQueue, elem, tmp) {
+ waypointp = (waypoint *) elem;
+ if (0 == strcmp(waypointp->shortname, name)) {
+ return waypointp;
+ }
+ }
+ return NULL;
+}
+
+const char *
+gdb_find_desc_from_icon_number(const int icon, garmin_formats_e garmin_format)
+{
+ icon_mapping_t *i;
+
+ for (i = garmin_icon_table; i->icon; i++) {
+ switch (garmin_format) {
+ case MAPSOURCE:
+ if (icon == i->mpssymnum)
+ return i->icon;
+ break;
+ case PCX:
+ case GARMIN_SERIAL:
+ if (icon == i->pcxsymnum)
+ return i->icon;
+ break;
+ default:
+ fatal(MYNAME ": unknown garmin format");
+ }
+ }
+ return DEFAULTICONDESCR;
+}
+
+/* %%% local functions (read support) %%% */
+
+char *
+gdb_convert_name_buff(char *buff, size_t buffsize)
+{
+#ifdef UTF8_SUPPORT
+ char *tmp = str_garmin_to_utf8(buff);
+ strncpy(buff, tmp, buffsize);
+ xfree(tmp);
+#endif
+ return buff;
+}
+
+#ifdef GDB_DEBUG
+static void
+gdb_print_buff(const char *buff, int count, const char *comment)
+{
+ int i;
+ printf(MYNAME ": dump of %s : ", comment);
+ for (i = 0; i < count; i++)
+ {
+ printf("%02x ", buff[i] & 0xFF);
+ }
+ printf("\n");
+ fflush(stdout);
+}
+#endif
+
+waypoint *
+gdb_create_rte_wpt(const char *name, double lat, double lon, double alt)
+{
+ waypoint *wpt;
+
+ wpt = find_waypt_by_name(name);
+ if (wpt != NULL) wpt = waypt_dupe(wpt);
+ else
+ {
+ gdb_find_wpt_q_by_name((queue *)&gdb_hidden->waypoint_list, name);
+ if (wpt != NULL) wpt = waypt_dupe(wpt);
+ else
+ {
+ wpt = waypt_new();
+ wpt->shortname = xstrdup(name);
+ wpt->latitude = lat;
+ wpt->longitude = lon;
+ wpt->altitude = alt;
+ wpt->depth = unknown_alt;
+ }
+ }
+ return wpt;
+}
+
+
+static unsigned int
+gdb_fread_str(FILE *fin, char *dest, size_t maxlen)
+{
+ int c;
+ unsigned int res = 0;
+
+ while (maxlen-- > 0)
+ {
+ c = fgetc(fin);
+ if ( c != EOF )
+ {
+ *dest++ = c;
+ if ( c == 0 ) return res;
+ res++;
+ }
+ else
+ {
+ *dest++ = '\0';
+ return res;
+ }
+ }
+ fatal(MYNAME ": local buffer overflow detected, please report!\n");
+}
+
+static int
+gdb_fread_le(FILE *fin, void *dest, size_t size, unsigned int bit_count, const char *field)
+{
+ char buff[32];
+ unsigned char *c = dest;
+ short *sh = dest;
+ int *li = dest;
+ double *db = dest;
+
+ if ((bit_count >> 3) != size)
+ fatal(MYNAME ": internal error (gdb_le_read/%d/%d/%s)!\n", size, bit_count >> 3, field);
+
+ switch(bit_count)
+ {
+ case 8:
+ fread(c, sizeof(*c), 1, fin);
+ if (gdb_debug) printf(MYNAME ": gdb_fread_le : %d -> %s (0x%x))\n", *c, field, *c);
+ return *c;
+ case 16:
+ if (sizeof(*sh) != size) fatal(MYNAME ": internal decl.!\n");
+ fread(sh, sizeof(*sh), 1, fin);
+ *sh = le_read16(sh);
+ if (gdb_debug) printf(MYNAME ": gdb_fread_le : %d -> %s (0x%x))\n", *sh, field, *sh);
+ return *sh;
+ case 32:
+ fread(li, 4, 1, fin);
+ *li = le_read32(li);
+ if (gdb_debug) printf(MYNAME ": gdb_fread_le : %d -> %s (0x%x)\n", *li, field, *li);
+ return *li;
+ case 64:
+ fread(buff, sizeof(*db), 1, fin);
+ le_read64(db, buff);
+ if (gdb_debug) printf(MYNAME ": gdb_fread_le : %g -> %s\n", *db, field);
+ return 0;
+ default:
+ fatal(MYNAME ": unsupported bit count (%d) in gdb_le_read!\n", bit_count);
+ }
+}
+
+static void
+gdb_is_valid(int is, const char *comment)
+{
+ if (is == 0) fatal(MYNAME ": error in database structure (%s)!\n", comment);
+}
+
+static void
+gdb_read_file_header(void)
+{
+ char buff[128];
+ int i;
+ unsigned int reclen;
+
+ i = gdb_fread_str(fin, buff, sizeof(buff));
+ if ( i != 5 )
+ fatal(MYNAME ": invalid database!\n");
+
+ if (strcmp(buff, "MsRcf") != 0)
+ fatal(MYNAME ": invalid database!\n");
+
+ fread(&reclen, 4, 1, fin);
+ reclen = le_read32(&reclen);
+
+ gdb_is_valid(reclen == gdb_fread_str(fin, buff, sizeof(buff)), "header");
+
+ gdb_is_valid(buff[0] == 'D', "header");
+ switch(buff[1])
+ {
+ case 'k':
+ gdb_ver = 1;
+ break;
+ case 'l':
+ gdb_ver = 2;
+ break;
+ default:
+ fatal(MYNAME ": non supported gdb version!\n");
+ }
+
+ if (global_opts.verbose_status > 0)
+ printf(MYNAME ": found Garmin GPS Database version %d\n", gdb_ver);
+
+ fread(&reclen, 4, 1, fin);
+ reclen = le_read32(&reclen);
+ gdb_is_valid(reclen < sizeof(buff), "header");
+ fread(buff, reclen, 1, fin);
+
+ gdb_is_valid(0 == gdb_fread_str(fin, buff, sizeof(buff)), "header");
+
+ i = gdb_fread_str(fin, buff, sizeof(buff));
+ gdb_is_valid((i == 9) && (strcmp(buff, "MapSource") == 0), "header");
+}
+
+waypoint *
+gdb_read_wpt(const size_t fileofs, int *wptclass)
+{
+ char xname[MPSNAMEBUFFERLEN];
+ char xdesc[MPSDESCBUFFERLEN];
+ char xnotes[MPSNOTESBUFFERLEN];
+ int xclass;
+ int xlat, xlon, xdisplay, xcolour, xicon, xtime;
+ short xcat;
+ double xdepth = unknown_alt;
+ double xalt = unknown_alt;
+
+ char buff[128];
+
+ size_t pos, delta;
+
+
+/********************************************************************************************************/
+/* record structure
+
+ zstring name
+ dword class
+ zstring country
+ 4 * 0x00 subclass part 1
+ 12 * 0xFF subclass part 2
+ 2 * 0x00 subclass part 3
+ 4 * 0xFF unknown
+ dword latitude
+ dword longitude
+ if (1) +8 altitude = (1 or 9)
+ zstring comment
+ dword display flag
+ dword display colour
+ dword icon
+ zstring city ?
+ zstring state ?
+ zstring facility ?
+ char unknown ?
+ double depth (if flag)
+ zstring url
+ word category -> offset 79
+ double temp (if flag)
+ */
+/********************************************************************************************************/
+
+ gdb_is_valid(gdb_fread_str(fin, xname, sizeof(xname)) > 0, "new waypoint");
+ gdb_convert_name_buff(xname, sizeof(xname));
+
+ gdb_fread_le(fin, &xclass, sizeof(xclass), 32, "xclass");
+ gdb_fread_str(fin, buff, sizeof(buff)); /* country */
+
+ fread(buff, 22, 1, fin);
+ xlat = gdb_fread_le(fin, &xlat, sizeof(xlat), 32, "xlat"); /* latitude */
+ xlon = gdb_fread_le(fin, &xlon, sizeof(xlon), 32, "xlon"); /* latitude */
+
+ fread(buff, 1, 1, fin);
+ if (buff[0] == 1) /* altitude flag */
+ {
+ gdb_fread_le(fin, &xalt, sizeof(xalt), 64, "xalt"); /* altitude */
+ }
+
+ gdb_fread_str(fin, xdesc, sizeof(xdesc));
+ gdb_convert_name_buff(xdesc, sizeof(xdesc));
+
+ fread(buff, 1, 1, fin); /* proximity flag */
+ if (buff[0] == 1)
+ {
+ fread(buff, 8, 1, fin); /* proximity */
+ }
+
+ xdisplay = gdb_fread_le(fin, &xdisplay, sizeof(xdisplay), 32, "xdisplay");
+ xcolour = gdb_fread_le(fin, &xcolour, sizeof(xcolour), 32, "xcolour");
+ xicon = gdb_fread_le(fin, &xicon, sizeof(xicon), 32, "xicon");
+
+ /* ToDo: convert the icon !!! */
+
+ gdb_fread_str(fin, buff, sizeof(buff)); /* city */
+ gdb_fread_str(fin, buff, sizeof(buff)); /* state */
+ gdb_fread_str(fin, buff, sizeof(buff)); /* facility */
+ fread(buff, 1, 1, fin); /* unknown */
+
+ fread(buff, 1, 1, fin); /* depth flag */
+ if (buff[0] == 1)
+ {
+ gdb_fread_le(fin, &xdepth, sizeof(xdepth), 64, "xdepth"); /* depth */
+ }
+
+ fread(buff, 1, 1, fin);
+ fread(buff, 1, 1, fin);
+ fread(buff, 1, 1, fin);
+
+ if (buff[0] != 0)
+ fread(buff, 3, 1, fin);
+ else
+ fread(buff, 4, 1, fin);
+
+ gdb_fread_str(fin, xnotes, sizeof(xnotes));
+ gdb_convert_name_buff(xnotes, sizeof(xnotes));
+
+ xcat = gdb_fread_le(fin, &xcat, sizeof(xcat), 16, "xcat");
+
+ fread(buff, 1, 1, fin); /* temperature flag */
+ if (buff[0] == 1)
+ {
+ fread(buff, 8, 1, fin); /* temperature */
+ }
+
+ /* Here comes 1 .. 6 unknown bytes
+ !!! 6 only if class > 0 !!!
+ the field seems to be a time stamp */
+
+ pos = ftell(fin);
+ delta = fileofs - pos;
+ gdb_is_valid(delta > 0, "waypoint final");
+
+ xtime = 0;
+ if (xclass == 0)
+ {
+ fread(buff, 1, 1, fin);
+ if (buff[0] == 1)
+ {
+ gdb_is_valid(delta==5, "??? waypoint time ???");
+ gdb_fread_le(fin, &xtime, sizeof(xtime), 32, "xtime");
+ }
+ else
+ gdb_is_valid(delta==1, "no waypoint time");
+ }
+
+ *wptclass = xclass;
+
+ waypoint *res = waypt_new();
+ res->shortname = xstrdup(xname);
+ res->description = xstrdup(xdesc);
+ res->notes = xstrdup(xnotes);
+ res->latitude = GPS_Math_Semi_To_Deg(xlat);
+ res->longitude = GPS_Math_Semi_To_Deg(xlon);
+ res->altitude = xalt;
+ res->creation_time = xtime;
+ /* might need to change this to handle version dependent icon handling */
+ res->icon_descr = gdb_find_desc_from_icon_number(xicon, MAPSOURCE);
+
+ return res;
+}
+
+static void
+gdb_read_route(void)
+{
+ char xname[MPSNAMEBUFFERLEN];
+ char xwptname[MPSNAMEBUFFERLEN];
+ int xclass;
+ double xalt;
+ double xlat = 0.0, xlon = 0.0;
+
+ char buff[256];
+ int count;
+ int isteps, ilink;
+ int semilat, semilon;
+
+ route_head *route;
+ waypoint *wpt;
+
+ unsigned int i, j;
+ size_t curpos;
+
+ gdb_is_valid(gdb_fread_str(fin, xname, sizeof(xname)) > 0, "route start");
+ gdb_convert_name_buff(xname, sizeof(xname));
+
+ gdb_fread_le(fin, buff, 2, 16, "auto_name");
+ gdb_fread_le(fin, buff, 4, 32, "max_lat");
+ gdb_fread_le(fin, buff, 4, 32, "max_lon");
+
+ fread(buff, 1, 1, fin);
+ if (buff[0] == 1) gdb_fread_le(fin, buff, 8, 64, "max_alt");
+
+ gdb_fread_le(fin, buff, 4, 32, "min_lat");
+ gdb_fread_le(fin, buff, 4, 32, "min_lon");
+
+ fread(buff, 1, 1, fin);
+ if (buff[0] == 1) gdb_fread_le(fin, buff, 8, 64, "min_alt");
+
+ gdb_fread_le(fin, &count, sizeof(count), 32, "rte_count");
+ if (count <= 0) return;
+
+ route = route_head_alloc();
+ route->rte_name = xstrdup(xname);
+ route_add_head(route);
+
+#if GDB_DEBUG
+ printf(MYNAME " - route: \"%s\" with %d point(s)\n", route->rte_name, count);
+#endif
+
+ if (count <= 0) return;
+
+ count--;
+
+ while (count--)
+ {
+ gdb_fread_str(fin, xwptname, sizeof(xwptname)); /* name */
+ gdb_convert_name_buff(xwptname, sizeof(xwptname));
+
+ gdb_fread_le(fin, &xclass, sizeof(xclass), 32, "xclass"); /* class */
+ gdb_fread_str(fin, buff, sizeof(buff)); /* country */
+
+ fread(buff, 22, 1, fin); /* sub class data */
+ i = 0;
+ while (i < sizeof(buff))
+ {
+ fread(&buff[i], 1, 1, fin);
+ if (buff[i] == 0) break;
+ i++;
+ }
+
+ /* The next thing is the unknown 0x03 0x00 .. 0x00 (18 bytes) */
+ fread(buff, 18, 1, fin);
+
+ gdb_fread_le(fin, &isteps, sizeof(isteps), 32, "isteps");
+
+ if (isteps <= 0) return;
+
+ gdb_fread_le(fin, &semilat, sizeof(semilat), 32, "semilat");
+ gdb_fread_le(fin, &semilon, sizeof(semilon), 32, "semilon");
+ xlat = GPS_Math_Semi_To_Deg(semilat);
+ xlon = GPS_Math_Semi_To_Deg(semilon);
+
+ gdb_is_valid(fabs(xlat) < 180.0 && fabs(xlon) < 180.0, " - rte: read loop: invalid lat or lon");
+ gdb_is_valid(fabs(xlat) > 1 && fabs(xlon) > 1, " - rte: read loop: invalid lat or lon");
+
+ xalt = unknown_alt;
+ fread(buff, 1, 1, fin); /* altitude flag */
+ if (buff[0] == 1)
+ {
+ gdb_fread_le(fin, &xalt, sizeof(xalt), 64, "xalt");
+ }
+ gdb_is_valid(xlat > 1 && xlon > 1, " - rte: read loop");
+
+ wpt = gdb_create_rte_wpt(xwptname, xlat, xlon, xalt);
+ route_add_wpt(route, wpt);
+
+ for (ilink = isteps-1; ilink > 0; ilink--)
+ {
+ gdb_fread_le(fin, &semilat, sizeof(semilat), 32, "semilat");
+ gdb_fread_le(fin, &semilon, sizeof(semilon), 32, "semilon");
+ fread(buff, 1, 1, fin); /* altitude flag */
+ if (buff[0] == 1) gdb_fread_le(fin, &xalt, sizeof(xalt), 64, "xalt");
+ xlat = GPS_Math_Semi_To_Deg(semilat);
+ xlon = GPS_Math_Semi_To_Deg(semilon);
+ gdb_is_valid(xlat > 1 && xlon > 1, " - rte/ils: read loop: invalid lat or lon");
+ }
+
+ fread(buff, 1, 1, fin); /* NULL */
+ gdb_is_valid(buff[0] == 0, "should be zero byte");
+
+ fread(buff, 4, 1, fin); /* link max lat */
+ fread(buff, 4, 1, fin); /* link max lon */
+ fread(buff, 1, 1, fin);
+ if (buff[0] == 1)
+ {
+ fread(buff, 8, 1, fin); /* link max alt validity + alt */
+ }
+ fread(buff, 4, 1, fin); /* link min lat */
+ fread(buff, 4, 1, fin); /* link min lon */
+
+ fread(buff, 1, 1, fin);
+ if (buff[0] == 1)
+ {
+ fread(buff, 8, 1, fin); /* link min alt validity + alt */
+ }
+
+ /* find the end of the record */
+
+ curpos = ftell(fin);
+
+ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ the stuff here is very tricky and did not base on any
+ any knowledgement, but seems to work.
+ The final structure varied from file to file and i
+ could not find any connection with data, gdb version
+ and any unknown bytes and bits. Hmm.
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+ memset(buff, 0, sizeof(buff));
+ int checked = 0;
+
+ j = 18;
+ while (checked == 0 && j-- > 0)
+ {
+ for (i=1; i<8; i++) buff[i-1] = buff[i];
+ fread(&buff[7], 1, 1, fin);
+ for (i=0; i<8; i++)
+ {
+ if (buff[i] != -1) break;
+ if (i == 7) checked = 1;
+ }
+
+ }
+ if (checked == 0)
+ {
+ fseek(fin, curpos, SEEK_SET);
+ }
+ else
+ {
+ while (1)
+ {
+ fread(buff, 1, 1, fin);
+ if (buff[0] != -1)
+ {
+ fseek(fin, ftell(fin)-1, SEEK_SET);
+ break;
+ }
+ }
+
+ }
+ }
+
+ gdb_fread_str(fin, xwptname, sizeof(xwptname)); /* name */
+ gdb_convert_name_buff(xwptname, sizeof(xwptname));
+
+#if GDB_DEBUG
+ printf(MYNAME " - rte/fin: \"%s\"\n", xwptname);
+#endif
+ gdb_fread_le(fin, &xclass, sizeof(xclass), 32, "xclass"); /* class */
+ gdb_fread_str(fin, buff, sizeof(buff)); /* country */
+
+ wpt = gdb_create_rte_wpt(xwptname, xlat, xlon, xalt);
+ route_add_wpt(route, wpt);
+
+ return;
+}
+
+
+route_head *
+gdb_read_track(const size_t max_file_pos)
+{
+ char xname[MPSNAMEBUFFERLEN];
+ unsigned char xdisplay;
+ int xcolour;
+ int xlat;
+ int xlon;
+ int xtime = 0;
+ double xalt = unknown_alt;
+ double xdepth = unknown_alt;
+ double xtemp;
+
+ char buff[128];
+ int count;
+
+ route_head *track;
+ waypoint *wpt;
+
+ gdb_fread_str(fin, xname, sizeof(xname));
+ gdb_convert_name_buff(xname, sizeof(xname));
+
+ gdb_fread_le(fin, &xdisplay, sizeof(xdisplay), 8, "xdisplay");
+ gdb_fread_le(fin, &xcolour, sizeof(xcolour), 32, "xcolour");
+ gdb_fread_le(fin, &count, sizeof(count), 32, "count");
+
+ track = route_head_alloc();
+ track->rte_name = xstrdup(xname);
+ track_add_head(track);
+
+ while (count > 0)
+ {
+ count--;
+
+ gdb_fread_le(fin, &xlat, sizeof(xlat), 32, "xlat");
+ gdb_fread_le(fin, &xlon, sizeof(xlon), 32, "xlon");
+
+ fread(buff, 1, 1, fin); /* altitude flag */
+ if (buff[0] == 1)
+ gdb_fread_le(fin, &xalt, sizeof(xalt), 64, "xalt");
+
+ fread(buff, 1, 1, fin); /* date/time flag */
+ if (buff[0] == 1)
+ gdb_fread_le(fin, &xtime, sizeof(xtime), 32, "xtime");
+
+ fread(buff, 1, 1, fin); /* depth flag */
+ if (buff[0] == 1)
+ gdb_fread_le(fin, &xdepth, sizeof(xdepth), 64, "xdepth");
+
+ fread(buff, 1, 1, fin);
+ if (buff[0] == 1)
+ gdb_fread_le(fin, &xtemp, sizeof(xtemp), 64, "xtemp");
+
+#if GDB_DEBUG
+ printf("trk: %g - %g (%08x - %08x)\n",
+ GPS_Math_Semi_To_Deg(xlat), GPS_Math_Semi_To_Deg(xlon), xlat, xlon);
+#endif
+
+ wpt = waypt_new();
+
+ wpt->latitude = GPS_Math_Semi_To_Deg(xlat);
+ wpt->longitude = GPS_Math_Semi_To_Deg(xlon);
+ wpt->creation_time = xtime;
+ wpt->centiseconds = 0;
+ wpt->altitude = xalt;
+ wpt->depth = xdepth;
+
+ route_add_wpt(track, wpt);
+ }
+
+ return track;
+}
+
+
+static void
+gdb_read_data(void)
+{
+ int reclen, done;
+ char typ;
+ size_t curpos, deltapos;
+ waypoint *wpt;
+ int wptclass;
+
+ done = 0;
+ while (!feof(fin) && (done == 0))
+ {
+
+ gdb_fread_le(fin, &reclen, sizeof(reclen), 32, "reclen");
+ gdb_is_valid(reclen > 0 && reclen < 0x1F00000, "gdb data loop");
+ fread(&typ, 1, 1, fin);
+ curpos = ftell(fin);
+
+ switch(typ)
+ {
+ case 'W':
+ wpt = gdb_read_wpt(curpos + reclen, &wptclass);
+ if (wpt != NULL )
+ {
+ if (wptclass == 0)
+ waypt_add(wpt);
+ else
+ route_add_wpt(gdb_hidden, wpt);
+ }
+ deltapos = (curpos+reclen)-ftell(fin);
+ break;
+ case 'T':
+ gdb_read_track(curpos + reclen);
+ break;
+ case 'R':
+ gdb_read_route();
+ break;
+ case 'L':
+ break;
+ case 'V':
+ done = 1;
+ break;
+ default:
+ printf(MYNAME ": found unknown record type \"%c\"!\n", typ);
+ }
+ fseek(fin, curpos + reclen, SEEK_SET);
+ }
+}
+
+/* %%% gobal callbacks %%% */
+
+static void gdb_rd_init(const char *fname)
+{
+ fin_name = xstrdup(fname);
+ fin = xfopen(fname, "rb", MYNAME);
+ gdb_hidden = route_head_alloc();
+ track_add_head(gdb_hidden);
+}
+
+static void gdb_rd_deinit(void)
+{
+ track_del_head(gdb_hidden);
+ fclose(fin);
+ xfree(fin_name);
+}
+
+static void gdb_read(void)
+{
+ gdb_read_file_header();
+ gdb_read_data();
+}
+
+
+ff_vecs_t gdb_vecs = {
+ ff_type_file,
+ { ff_cap_read, ff_cap_read, ff_cap_read }, /* FF_CAP_RW_ALL, */
+ gdb_rd_init,
+ NULL, /* gdb_wr_init, */
+ gdb_rd_deinit,
+ NULL, /* gdb_wr_deinit, */
+ gdb_read,
+ NULL, /* gdb_write, */
+ NULL,
+ NULL /* gdb_args */
+};